import * as THREE from 'three';
import Stats from 'three/examples/jsm/libs/stats.module.js';
import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls.js';
import {TransformControls} from 'three/examples/jsm/controls/TransformControls.js';
import {DragControls} from 'three/examples/jsm/controls/DragControls.js';
import {FirstPersonControls} from 'three/examples/jsm/controls/FirstPersonControls.js';
// import {FlyControls} from 'three/examples/jsm/controls/FlyControls.js';

import {GLTFLoader} from 'three/examples/jsm/loaders/GLTFLoader.js';
import CameraControls from 'camera-controls';

export class VRHall {    
  constructor(options) {
    this._options = Object.assign({
        container: document.body
    }, options);
    // 加载器
    this._gltfLoader = new GLTFLoader();
    //纹理贴图加载器
    this._textureLoader = new THREE.TextureLoader();
    // 时间
    this._clock=new THREE.Clock();
    // 可点击事件物体
    this._eventMesh=[]

    this._init();
    this._animate();
  }
  _init() {
    // 渲染器
    this._renderer = new THREE.WebGLRenderer({
        antialias: true // 抗锯齿
    });
    this._renderer.setPixelRatio(window.devicePixelRatio);// 设置设备像素比
    const {clientWidth, clientHeight} = this._options.container;// 获取容器宽高
    this._renderer.setSize(clientWidth, clientHeight);// 设置渲染器大小
    //this._renderer.setClearColor(0x000000, 1);// 设置背景色
    this._options.container.appendChild(this._renderer.domElement);// 将渲染器添加到容器中

    // 场景
    this._scene = new THREE.Scene();
    
    // 相机
    this._cameraPersp =  new THREE.PerspectiveCamera(75, clientWidth / clientHeight, 0.1, 1000);// 创建透视相机
    this._cameraOrtho = new THREE.OrthographicCamera(clientWidth / - 16, clientWidth / 16, clientHeight / 16, clientHeight / - 16, 0.1, 1000);// 创建正交相机
    this._camera = this._cameraPersp; //默认使用透视相机
    this._camera.position.set(0, 2, 10);// 设置相机位置
    this._camera.lookAt(0, 0, 0);// 相机看向坐标原点
    this._scene.add(this._camera);

    //渲染器渲染
    this._renderer.render(this._scene, this._camera);//

    // 光源
    this._initLight();

    //坐标轴
    this._initAxesHelper();

    //网格帮助器
    this._initGridHelper();

    //轨道控制器
    this._initOrbitControls();

    //变换控制器
    this._initTransformControls();

    //相机控制器
    //this._initCameraControls();

    //飞行控制器(无法用)
    //this._initFlyControls();

    //第一人称控制器
    //this._initFirstPersonControls();

    // 加载初始场景物体
    this._initMesh();

    //性能插件
    this._initStats();

    //射线捕获事件
    this._initRaycaster();

    // 事件监听初始化
    this._initEventListener();
   
  }

  _initEventListener(){
    // 处理窗口大小改变事件
    window.addEventListener( 'resize', this._onWindowResize.bind(this) );

    const that=this;
    const control = that._transformControls;
    const orbit = that._orbitControls;
    const cameraPersp = that._cameraPersp;
    const cameraOrtho = that._cameraOrtho;
    that._camera = cameraPersp;
    //处理键盘事件
    window.addEventListener( 'keydown', function ( event ) {   
      console.log(control.object);
      if(!control.object)
        return;
      switch ( event.keyCode ) {
        case 81: // Q
          control.setSpace( control.space === 'local' ? 'world' : 'local' );
          break;

        case 16: // Shift
          control.setTranslationSnap( 100 );
          control.setRotationSnap( THREE.MathUtils.degToRad( 15 ) );
          control.setScaleSnap( 0.25 );
          break;

        case 84: // T
          control.setMode( 'translate' );
          break;

        case 82: // R
          control.setMode( 'rotate' );
          break;

        case 83: // S
          control.setMode( 'scale' );
          break;

        case 67: // C
          const position = that._camera.position.clone();

          that._camera = that._camera.isPerspectiveCamera ? cameraOrtho : cameraPersp;
          that._camera.position.copy( position );

          orbit.object = that._camera;
          control.camera = that._camera;

          that._camera.lookAt( orbit.target.x, orbit.target.y, orbit.target.z );
          that._onWindowResize();
          break;

        case 86: // V
          const randomFoV = Math.random() + 0.1;
          const randomZoom = Math.random() + 0.1;

          cameraPersp.fov = randomFoV * 160;
          cameraOrtho.bottom = - randomFoV * 500;
          cameraOrtho.top = randomFoV * 500;

          cameraPersp.zoom = randomZoom * 5;
          cameraOrtho.zoom = randomZoom * 5;
          that._onWindowResize();
          break;

        case 187:
        case 107: // +, =, num+
          control.setSize( control.size + 0.1 );
          break;

        case 189:
        case 109: // -, _, num-
          control.setSize( Math.max( control.size - 0.1, 0.1 ) );
          break;

        case 88: // X
          control.showX = ! control.showX;
          break;

        case 89: // Y
          control.showY = ! control.showY;
          break;

        case 90: // Z
          control.showZ = ! control.showZ;
          break;

        case 32: // Spacebar
          control.enabled = ! control.enabled; 
          if(control.object){
            if(control.enabled){
              control.showX = true;
              control.showY = true;
              control.showZ = true;
              //control.attach(control.object );                
            }
            else{
              control.showX = false;
              control.showY = false;
              control.showZ = false;
              //control.detach();
            }
          }else{
           
          }        
          break;

        case 27: // Esc
          control.reset();
          break;

      }

    } );

    window.addEventListener( 'keyup', function ( event ) {

      switch ( event.keyCode ) {

        case 16: // Shift
          control.setTranslationSnap( null );
          control.setRotationSnap( null );
          control.setScaleSnap( null );
          break;

      }

    } );
  }

  _initStats(){
    this._stats = new Stats();
    this._stats.showPanel( 0 ); // 0: fps, 1: ms, 2: mb, 3+: custom
    document.body.appendChild( this._stats.dom );
  }

  _initMesh(){
    const cube = new THREE.Mesh(
      new THREE.BoxGeometry(1, 1, 1),
      new THREE.MeshBasicMaterial({color: 0x00ff00})
    );
    cube.position.x = -2;// 设置物体位置
    cube.name='Cube';// 设置物体的名字
    this._eventMesh.push(cube);// 将物体添加到事件物体数组中
    this._scene.add(cube);// 添加到场景中

  }

  _initRaycaster() {
    const rayCaster = new THREE.Raycaster();
    const pointer = new THREE.Vector2();

    this._options.container.addEventListener('click', (event) => {  
      const {clientWidth, clientHeight} = this._options.container;// 获取容器宽高

      pointer.x = ( event.clientX / clientWidth ) * 2 - 1;
      pointer.y = - ( event.clientY / clientHeight ) * 2 + 1;

      rayCaster.setFromCamera( pointer, this._camera );// 设置射线
      const intersects = rayCaster.intersectObjects( this._eventMesh );// 计算射线经过的所有可点击物体
      const intersect = intersects[0];
      if (intersect) {
        // console.log(intersect);
        const v3=intersect.point;// 获取点击位置
        console.log(v3);
        const control=this._transformControls;
        control.attach(intersect.object);// 绑定变换控制器
        control.enabled=true;// 启用变换控制器
        control.showX=true;
        control.showY=true;
        control.showZ=true;
        // if(intersect.object.name==='Cube'){
        //   console.log(intersect.object)
        // }
      }
    });
  }

  _initLight(){
    const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
    this._scene.add(ambientLight);

    // // 灯光
    // const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
    // directionalLight.position.set(0, 1, 0);
    // this._scene.add(directionalLight);
  }

  _initAxesHelper(){
    const axesHelper = new THREE.AxesHelper(5);
    this._scene.add(axesHelper);
  }

  _initGridHelper(){
    const gridHelper = new THREE.GridHelper(10, 10);
    this._scene.add(gridHelper);
  }

 _initOrbitControls() {
    this._orbitControls = new OrbitControls(this._camera, this._renderer.domElement);
    //this._orbitControls.target.set(0, 2, 0);
    this._orbitControls.update();
  }

  _initCameraControls() {
    this._cameraControls = new CameraControls(this._camera, this._renderer.domElement);
    //this._cameraControls.update();
  }

  // _initFlyControls() {  
  //   this._flyControls = new FlyControls(this._camera, this._renderer.domElement);
  //   // this._flyControls.movementSpeed = 10;
  //   // this._flyControls.domElement = this._renderer.domElement;
  //   // this._flyControls.rollSpeed = Math.PI / 24;
  //   // this._flyControls.autoForward = false;
  //   this._flyControls.dragToLook = true;//开启鼠标拾取
  //   this._flyControls.update();
  // }

  _initFirstPersonControls(){
    this._firstPersonControls = new FirstPersonControls(this._camera, this._renderer.domElement);
    this._firstPersonControls.activeLook=false;//关闭鼠标拾取
    // this._firstPersonControls.movementSpeed = 10;
    // this._firstPersonControls.lookSpeed = 0.1;
  }

  _initTransformControls () {
    this._transformControls = new TransformControls(this._camera, this._renderer.domElement );
    // this._transformControls.addEventListener( 'objectChange', function () {
    //   const object = this._transformControls.object
    // });
    this._transformControls.setSpace( 'local' );
    this._transformControls.setMode( 'translate');

    // //鼠标按下事件
    // this._transformControls.addEventListener('mouseDown', () =>{
    //     if(this._orbitControls)
    //         this._orbitControls.enabled=false; //禁用轨道控制器
    // });
    // //鼠标松开事件
    // this._transformControls.addEventListener('mouseUp', () =>{
    //     if(this._orbitControls)
    //       this._orbitControls.enabled=true; //启用用轨道控制器
    // });
    const that=this;
    this._transformControls.addEventListener( 'dragging-changed', function ( event ) {
      that._orbitControls.enabled = ! event.value; //启用/禁用轨道控制器
    });

    //对象变换事件
    this._transformControls.addEventListener('objectChange', () => {
        const {position,rotation,scale} = this._transformControls.object;
        console.log(JSON.stringify({position,rotation:{x:rotation.x,y:rotation.y,z:rotation.z},scale})); //获取变换后的位置
    }); 
    this._scene.add(this._transformControls);
  }

   _onWindowResize() {
    //console.log(this._options)
    const {clientWidth, clientHeight} = this._options.container;// 获取容器宽高
    const aspect = clientWidth / clientHeight;
    // this._camera.aspect = clientWidth / clientHeight;
    // this._camera.updateProjectionMatrix();
    this._cameraPersp.aspect = aspect;
    this._cameraPersp.updateProjectionMatrix();

    this._cameraOrtho.left = this._cameraOrtho.bottom * aspect;
    this._cameraOrtho.right = this._cameraOrtho.top * aspect;
    this._cameraOrtho.updateProjectionMatrix();

    this._renderer.setSize( clientWidth, clientHeight );// 设置渲染器宽高

    // this._camera.aspect = clientWidth / clientHeight;
    // this._camera.updateProjectionMatrix();
    // this._renderer.setSize( clientWidth, clientHeight );// 设置渲染器宽高
  }


  _animate() {
    const delta=this._clock.getDelta();
    requestAnimationFrame(() => {
        this._animate();
    });//循环渲染
    this._renderer.render(this._scene, this._camera);//渲染器渲染

    if(this._stats)
      this._stats.update();//更新性能插件

    if(this._orbitControls)
      this._orbitControls.update(delta);//更新轨道控制器

    if(this._cameraControls)
      this._cameraControls.update(delta);//更新相机控制器

    if(this._flyControls)
      this._flyControls.update(delta);//更新飞行控制器

    if(this._firstPersonControls)
      this._firstPersonControls.update(delta);//更新第一人称控制器
  }

  // 加载展厅
  async loadHall(params) {
    const {url,position,scale,onProgress}=params
    const gltf=await this.loadGltf({url,onProgress})
    const hall=gltf.scene 
    if(position){
      hall.position.set(position.x,position.y,position.z)
    }
    if(scale){
      hall.scale.set(scale.x,scale.y,scale.z)
    }
    this._eventMesh.push(hall)
    this._scene.add(hall)
    return gltf
  }
  // 加载场景物体
  loadGltf(params) {  
    const {url,onProgress}=params
    return new Promise((resolve, reject) => {
      this._gltfLoader.load(url, (gltf) => {      
        resolve(gltf)  
      },(progress)=> {    
        if(onProgress){
          onProgress(progress)
        }
      });   
    });      
  }

  // 加载纹理贴图
  loadTexture(params) {
    const {url,onProgress}=params
    return new Promise((resolve, reject) => {
      this._textureLoader.load(url, (texture) => {      
        resolve(texture)  
      },(progress)=> {    
        if(onProgress){
          onProgress(progress)
        }
      },(err)=>{
        console.error(err)
      });   
    });      
  }


  //测试用
  test1() {
    const cube = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), new THREE.MeshBasicMaterial({
      color: 0x00ff00
    }))

    const cube2 = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), new THREE.MeshBasicMaterial({
      color: 0x00ffff
    }))

    cube2.position.x = 2;

    const controls = new DragControls( [cube,cube2], this._camera, this._renderer.domElement );

    // add event listener to highlight dragged objects

    // controls.addEventListener( 'dragstart', function ( event ) {

      

    // } );

    // controls.addEventListener( 'dragend', function ( event ) {

    //   //event.object.material.emissive= 0x000000;

    // } );

    this._scene.add(cube,cube2);
  }

}